-- ShapeChangeM
-- Create by dengc
-- 宠物变身模块

module("ShapeChangeM", package.seeall);

-- 普通触发
TRIGGER_NORMAL = "normal";

-- 稍后触发
TRIGGER_LATER = "trigger_later";

-- 可重复变身
CHANGE_REPEATEDLY = "change_repeatedly";

-- 稍后触发，可重复变身
REPEATEDLY_LATER = "repeatedly_later";

-- 变身持续整个迷宫
DURING_FOREVER = "forever";

-- 变身持续本层
DURING_FLOOR = "hole_floor";

-- 变身持续一定回合
DURING_ROUND = "round";

-- 当前是否处于变身状态
local isInShapeChange = false;

-- 变身信息
local shapeChangeinfo = {};
local shapeChangeRows = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    shapeChangeinfo = {};
    shapeChangeRows = {};

    local shape_change_CSV = get_shape_change_CSV();
    for i = 1, #shape_change_CSV do
        local shapeId = shape_change_CSV[i].id;

        shapeChangeRows[i] = shape_change_CSV[i];
        shapeChangeinfo[shapeId] = shape_change_CSV[i];

        -- 解析动作帧范围
        parseActionFrameRange(shape_change_CSV[i]);
    end
end

-- 模块初始化
function init()
    loadCsv();

    -- 关注玩家属性扣除事件
    EventMgr.removeAll("ShapeChangeM");
    EventMgr.register("ShapeChangeM", event.COST_ATTRIB, function(args)
        whenCostAttrib(args);
    end);

    -- 关注玩家属性增加事件
    EventMgr.register("ShapeChangeM", event.BONUS_ATTRIB, function(args)
        whenAddAttrib(args);
    end);
end

-- 解析动作的帧范围
function parseActionFrameRange(info)
    -- 待机、受创、攻击、对自身施法、对他人施法
    local fields = { "idle_frame", "damaged_frame", "attack_frame",
                     "cast_me_frame", "cast_other_frame", "speak_frame"};

    for _, field in pairs(fields) do
        local range = info[field];
        if type(range) == 'string' and string.len(range) > 0 then
            if not string.startWith(range, "[") or not string.endWith(range, "]") then
                error(string.format("字段(%s)配置格式错误!", tostring(field)));
                return info;
            end

            local arr = string.explode(string.sub(range, 2, -2),",");
            if #arr ~= 2 then
                error(string.format("字段(%s)配置格式错误!", tostring(field)));
                return info;
            end

            info[field] = { tonumber(arr[1]), tonumber(arr[2]) };
        end
    end

    return info;
end

-- 检索任务信息
function query(shapeId, path)
    local m = shapeChangeinfo[shapeId];
    if not m or path == "" or not path then
        return m;
    else
        return m[path];
    end
end

-- 检索行
function queryRows(row, path)
    local m = shapeChangeRows[row];
    if not m or path == "" or not path then
        return m;
    else
        return m[path];
    end
end

-- 关注玩家属性扣除事件
function whenCostAttrib(args)
    local attribType = args["cost"];

    -- 玩家扣血
    if attribType == "hp" or attribType == "max_hp" then
        -- 尝试变身
        local maxHp = ME.user:queryAttrib("max_hp");
        local curHp = ME.user:queryAttrib("hp", 0);
        local shapeId = FormulaM.invoke("HP_NEED_SHAPE_CHANGE", ME.user, maxHp, curHp);
        if shapeId ~= -1 then
            if type(shapeId) == "number" then
                PropM.record(ME.user, { 808, shapeId, 1, -1 }, "shape_change");
            elseif shapeId == "restore" then
                EventMgr.fire(event.SHAPE_RESTORE, {["shape_id"] = shapeId, ["show_effect"] = true, });
            end
        end
    end
end

-- 关注玩家属性增加事件
function whenAddAttrib(args)
    local attribType = args["cost"];

    -- 玩家血量增加
    if attribType == "hp" or attribType == "max_hp" then
        -- 尝试变身
        local maxHp = ME.user:queryAttrib("max_hp");
        local curHp = ME.user:queryAttrib("hp", 0);
        local shapeId = FormulaM.invoke("HP_NEED_SHAPE_CHANGE", ME.user, maxHp, curHp);
        if shapeId ~= -1 then
            if type(shapeId) == "number" then
                PropM.record(ME.user, { 808, shapeId, 1, -1 }, "shape_change");
            elseif shapeId == "restore" then
                -- 清除变身属性
                PropM.deleteProp(ME.user, "shape_change");

                -- 抛出事件，还原模型
                EventMgr.fire(event.SHAPE_RESTORE, {["shape_id"] = shapeId, ["show_effect"] = true, });
            end
        end
    end
end

-- 根据宠物id获取shapeId
function queryShapeIdByClassId(classId)
    local shapeIdList = {};
    for _, c in pairs(shapeChangeRows) do
        if c["class_id"] == classId then
            table.insert(shapeIdList, c["id"]);
        end
    end

    -- id按从小到大进行排序
    local function sortId(id1, id2)
        return id1 < id2;
    end
    table.sort(shapeIdList, sortId);

    return shapeIdList;
end

-- 获取当前的变身信息
function getShapeChangeId(petId)
    local props = PropM.fetchProps(ME.user, "shape_change");
    for _, prop in ipairs(props) do
        -- 查询变身信息
        local shapeId = prop[2];
        local shapeInfo = query(shapeId);

        local activePet = ME.user:getActivePet();
        local classId = petId or activePet.classId;

        if shapeInfo then
            if classId == shapeInfo["class_id"] then
                return shapeId;
            end
        end
    end

    return -1;
end

-- 根据条件解析变身条件
-- @condition 目前支持-1,0,1,2四种配置
-- 当需要不马上触发只记录时配置为-1；当允许多次变身时配置为0；前两种兼有配置为2；默认配置为1；
function parseCondition(condition)
    local tag;
    if condition == -1 then
        tag = TRIGGER_NORMAL;
    elseif condition == 0 then
        tag = CHANGE_REPEATEDLY;
    elseif condition == 2 then
        tag = REPEATEDLY_LATER;
    else
        tag = TRIGGER_NORMAL;
    end

    return tag;
end

-- 解析变身持续条件
function parseDuringCondition(time)
    local during;
    if not time or time == -1 then
        -- 持续整个迷宫
        during = DURING_FOREVER;
    elseif time == 999 then
        -- 持续本层
        during = DURING_FLOOR;
    else
        -- 持续一定回合
        during = DURING_ROUND;
    end

    return during;
end

-- 获取是否处于变身状态
function getInShapeChange()
    return isInShapeChange;
end

-- 设置处于变身状态
function setInShapeChange(isShapeChange)
    isInShapeChange = isShapeChange;
end
